#include "Grid.h"


Grid::Grid(int rMax, int cMax, int stype) : PrimitiveObject(stype)
{
   rowMax = rMax;
   colMax = cMax;
   indexID = 0;
   numCoords = (rowMax + 1)*(colMax + 1);
   numIndex = 6 * rowMax*colMax;
   structType = stype;
}

void Grid::fill()
{
   if (structType == Vertex::type::P_N_AND_T) {
      //@TODO
      coordDataNC = new Vertex::PNT[numCoords];
   }
   else if (structType == Vertex::type::P_AND_N) {
      coordDataN = new Vertex::PN[numCoords];
      for (int j = 0; j <= rowMax; j++) {
         for (int i = 0; i <= colMax; i++) {
            int k = index(i, j);
            coordDataN[k].v = glm::vec3((float)i / colMax - (0.5f), (float)j / rowMax - (0.5f), 0);
            coordDataN[k].n = glm::vec3(0, 0, 1.0f);
         }
      }
   }
   else {
      coordData = new glm::vec3[numCoords];
      for (int j = 0; j <= rowMax; j++) {
         for (int i = 0; i <= colMax; i++) {
            int k = index(i, j);
            coordData[k] = glm::vec3((float)i / colMax - (0.5f), (float)j / rowMax - (0.5f), 0);
         }
      }
   }

   indexData = new GLuint[numIndex];
   int k = 0;
   for (int j = 0; j < rowMax; j++) {
      for (int i = 0; i < colMax; i++) {
         indexData[k++] = index(i, j);
         indexData[k++] = index(i + 1, j + 1);
         indexData[k++] = index(i, j + 1);
         indexData[k++] = index(i, j);
         indexData[k++] = index(i + 1, j);
         indexData[k++] = index(i + 1, j + 1);
         //printf ("[%d] %d %d %d %d %d\n",k, indexData[k - 5], indexData[k - 4], indexData[k - 3], indexData[k - 2], indexData[k - 1]);
      }
   }
}

void Grid::genBuffer()
{

   glGenVertexArrays(1, &VAOHandle);
   glBindVertexArray(VAOHandle);

   if (structType == Vertex::type::P_N_AND_T) {
      //@TODO
   }
   else if (structType == Vertex::type::P_AND_N) {
      glGenBuffers(1, &vertexID);
      glBindBuffer(GL_ARRAY_BUFFER, vertexID);
      glBufferData(GL_ARRAY_BUFFER, numCoords*sizeof(Vertex::PN), coordDataN, GL_STATIC_DRAW);

      glEnableVertexAttribArray(attribLoc[0]); //position in shader
      glEnableVertexAttribArray(attribLoc[1]); //normal
      glVertexAttribPointer (attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex::PN), 0);
      glVertexAttribPointer (attribLoc[1], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex::PN), (GLvoid*)(sizeof(coordDataN[0].n)));
      delete[] coordDataN;
   }
   else {
      glGenBuffers(1, &vertexID);
      glBindBuffer(GL_ARRAY_BUFFER, vertexID);
      glBufferData(GL_ARRAY_BUFFER, numCoords*sizeof(glm::vec3), coordData, GL_STATIC_DRAW);
      glEnableVertexAttribArray(attribLoc[0]);
      glVertexAttribPointer (attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), NULL);
      delete[] coordData;
   }
   glGenBuffers(1, &indexID);
   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID);
   glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndex*sizeof(GLuint), indexData, GL_STATIC_DRAW);   
   delete[] indexData;
   glBindVertexArray(0);//free Bind

}

void Grid::init(void)
{
   fill();
   genBuffer();
}

void Grid::draw()
{
   glBindVertexArray(VAOHandle);
   glDrawElements(GL_TRIANGLES, numIndex, GL_UNSIGNED_INT, NULL);
   glBindVertexArray(0);
}

//@TODO - Review delete
void Grid::freeBuffer()
{
   if (structType == Vertex::type::P_N_AND_T) {
      //@TODO
   }
   else if (structType == Vertex::type::P_AND_N) {
      //@TODO
   }
   else {
      glDeleteBuffers(1, &vertexID);
      glDeleteBuffers(1, &indexID);
   }
}

int Grid::index(int i, int j)
{
   return i + j*(colMax + 1);
}

Grid::~Grid()
{   
   freeBuffer();
}
